﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using l1cs.server.model.Instance;

namespace l1cs.server.model
{
    public class L1HateList
    {
        private Dictionary<L1Character, int> _hateMap;

        private L1HateList( Dictionary<L1Character, int> hateMap )
        {
            _hateMap = hateMap;
        }

        public L1HateList()
        {
            /*
             * ConcurrentHashMapを利用するより、 全てのメソッドを同期する方がメモリ使用量、速度共に優れていた。
             * 但し、今後このクラスの利用方法が変わった場合、 例えば多くのスレッドから同時に読み出しがかかるようになった場合は、
             * ConcurrentHashMapを利用した方が良いかもしれない。
             */
            _hateMap = new Dictionary<L1Character, int>();
        }

        public void add( L1Character cha, int hate )
        {
            lock ( _hateMap )
            {
                if ( cha == null )
                {
                    return;
                }
                if ( _hateMap.ContainsKey( cha ) )
                {
                    _hateMap[cha] = _hateMap[cha] + hate;
                }
                else
                {
                    _hateMap[cha] = hate;
                }
            }
        }

        public int get( L1Character cha )
        {
            lock ( _hateMap )
            {
                int ret;
                _hateMap.TryGetValue( cha, out ret );
                return ret;
            }
        }

        public bool containsKey( L1Character cha )
        {
            lock ( _hateMap )
            {
                return _hateMap.ContainsKey( cha );
            }
        }

        public void remove( L1Character cha )
        {
            lock ( _hateMap )
            {
                _hateMap.Remove( cha );
            }
        }

        public void clear()
        {
            lock ( _hateMap )
            {
                _hateMap.Clear();
            }
        }

        public bool isEmpty()
        {
            lock ( _hateMap )
            {
                return _hateMap.Count == 0;
            }
        }

        public L1Character getMaxHateCharacter()
        {
            lock ( _hateMap )
            {
                L1Character cha = null;
                int hate = int.MinValue;// MIN_VALUE;

                foreach ( L1Character val in _hateMap.Keys )
                {
                    int key = _hateMap[val];
                    if ( hate < key )
                    {
                        cha = val;
                        hate = key;
                    }
                }
                return cha;
            }
        }

        public void removeInvalidCharacter( L1NpcInstance npc )
        {
            lock ( _hateMap )
            {
                List<L1Character> invalidChars = new List<L1Character>();
                foreach ( L1Character cha in _hateMap.Keys )
                {
                    if ( cha == null || cha.isDead() || !npc.knownsObject( cha ) )
                    {
                        invalidChars.Add( cha );
                    }
                }

                foreach ( L1Character cha in invalidChars )
                {
                    _hateMap.Remove( cha );
                }
            }
        }

        public int getTotalHate()
        {
            lock ( _hateMap )
            {
                int totalHate = 0;
                foreach ( int hate in _hateMap.Values )
                {
                    totalHate += hate;
                }
                return totalHate;
            }
        }

        public int getTotalLawfulHate()
        {
            lock ( _hateMap )
            {
                int totalHate = 0;
                foreach ( L1Character key in _hateMap.Keys )
                {
                    if ( key is L1PcInstance )
                    {
                        totalHate += _hateMap[key];
                    }
                }
                return totalHate;
            }
        }

        public int getPartyHate( L1Party party )
        {
            lock ( _hateMap )
            {
                int partyHate = 0;

                //foreach ( Map.Entry<L1Character, Integer> e in _hateMap.entrySet() )
                foreach ( L1Character key in _hateMap.Keys )
                {
                    L1PcInstance pc = null;
                    if ( key is L1PcInstance )
                    {
                        pc = (L1PcInstance)key;
                    }
                    if ( key is L1NpcInstance )
                    {
                        L1Character cha = ( (L1NpcInstance)key ).getMaster();
                        if ( cha is L1PcInstance )
                        {
                            pc = (L1PcInstance)cha;
                        }
                    }

                    if ( pc != null && party.isMember( pc ) )
                    {
                        partyHate += _hateMap[key];
                    }
                }
                return partyHate;
            }
        }

        public int getPartyLawfulHate( L1Party party )
        {
            lock ( _hateMap )
            {
                int partyHate = 0;

                //foreach ( Map.Entry<L1Character, Integer> e in _hateMap.entrySet() )
                foreach ( L1Character key in _hateMap.Keys )
                {
                    L1PcInstance pc = null;
                    if ( key is L1PcInstance )
                    {
                        pc = (L1PcInstance)key;
                    }

                    if ( pc != null && party.isMember( pc ) )
                    {
                        partyHate += _hateMap[key];
                    }
                }
                return partyHate;
            }
        }

        public L1HateList copy()
        {
            lock ( _hateMap )
            {
                return new L1HateList( new Dictionary<L1Character, int>( _hateMap ) );
            }
        }

        //public Set<Entry<L1Character, Integer>> entrySet()
        //{
        //    lock ( _hateMap )
        //    {
        //        return _hateMap.entrySet();
        //    }
        //}

        public List<L1Character> toTargetArrayList()
        {
            lock ( _hateMap )
            {
                return new List<L1Character>( _hateMap.Keys );
            }
        }

        public List<int> toHateArrayList()
        {
            lock ( _hateMap )
            {
                return new List<int>( _hateMap.Values );
            }
        }
    }
}
